package com.ht.shortlink.admin.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ht.shortlink.admin.common.biz.user.UserContext;
import com.ht.shortlink.admin.common.convention.exception.ClientException;
import com.ht.shortlink.admin.dao.entity.GroupDO;
import com.ht.shortlink.admin.dao.mapper.GroupMapper;
import com.ht.shortlink.admin.dto.req.ShortLinkGroupAddReqDTO;
import com.ht.shortlink.admin.dto.req.ShortLinkGroupSortReqDTO;
import com.ht.shortlink.admin.dto.req.ShortLinkGroupUpdateReqDTO;
import com.ht.shortlink.admin.dto.resp.ShortLinkGroupRespDTO;
import com.ht.shortlink.admin.remote.dto.ShortLinkRemoteService;
import com.ht.shortlink.admin.remote.dto.resp.ShortLinkGroupCountRespDTO;
import com.ht.shortlink.admin.service.IGroupService;
import lombok.RequiredArgsConstructor;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.ht.shortlink.admin.toolkit.RandomGenerator.generateRandomString;

/**
 *  短链接分组接口实现层
 */
@Service
@RequiredArgsConstructor
public class GroupServiceImpl extends ServiceImpl<GroupMapper, GroupDO> implements IGroupService {
    private final RedissonClient redissonClient;

    @Value("${short-link.group.max-sum}")
    private Integer groupMaxSum;

    // 后续重构为feign调用
    private ShortLinkRemoteService shortLinkRemoteService = new ShortLinkRemoteService() {
    };

    @Override
    public void add(ShortLinkGroupAddReqDTO requestParam) {
        add(UserContext.getUsername(), requestParam.getName());
    }

    @Override
    public void add(String username, String groupName) {
        RLock lock = redissonClient.getLock(String.format("LOCK_GROUP_CREATE_KEY", username));
        try{
            if(lock.tryLock()) {
                // 1、判断分组数是否超过20
                List<GroupDO> groupDOList = lambdaQuery().eq(GroupDO::getUsername, username)
                        .eq(GroupDO::getDelFlag, 0)
                        .list();
                if(CollUtil.isNotEmpty(groupDOList) && groupDOList.size() == groupMaxSum){
                    throw new ClientException(String.format("分组数超过最大限制数 %d", groupMaxSum));
                }
                // 2、生成随机的gid
                String gid;
                do {
                    gid = generateRandomString();
                } while (hasGid(username, gid));
                // 3、保存到数据库
                GroupDO groupDO = GroupDO.builder()
                        .gid(gid)
                        .username(username)
                        .name(groupName)
                        .sortOrder(0)
                        .build();

                save(groupDO);
            }
        }finally {
            lock.unlock();
        }
    }

    private boolean hasGid(String username, String gid) {
        GroupDO groupDO = lambdaQuery()
                .eq(GroupDO::getGid, gid)
                .eq(GroupDO::getUsername, username)
                .one();

        return groupDO != null;
    }

    @Override
    public void update(ShortLinkGroupUpdateReqDTO requestParam) {
        // 1、获取登录的用户名
        String username = UserContext.getUsername();
        // 2、更新分组名
        LambdaUpdateWrapper<GroupDO> wrapper = Wrappers.lambdaUpdate(GroupDO.class)
                .eq(GroupDO::getUsername, username)
                .eq(GroupDO::getGid, requestParam.getGid())
                .eq(GroupDO::getDelFlag, 0);
        GroupDO groupDO = new GroupDO();
        groupDO.setName(requestParam.getName());
        update(groupDO, wrapper);
    }

    @Override
    public List<ShortLinkGroupRespDTO> listGroup() {
        // 1、获取登录的用户名
        String username = UserContext.getUsername();
        // 2、查询分组集合
        List<GroupDO> groupDOList = lambdaQuery()
                .eq(GroupDO::getUsername, username)
                .eq(GroupDO::getDelFlag, 0)
                .orderByDesc(GroupDO::getSortOrder, GroupDO::getUpdateTime)
                .list();
        // 3、转化为响应实体
        if(CollUtil.isEmpty(groupDOList)){
            return Collections.emptyList();
        }

        // 4、设置分组下短链接数量
        List<ShortLinkGroupRespDTO> shortLinkGroupRespDTOS = BeanUtil.copyToList(groupDOList, ShortLinkGroupRespDTO.class);
        List<ShortLinkGroupCountRespDTO> countRespDTOS = shortLinkRemoteService.listGroupLinkCount(shortLinkGroupRespDTOS.stream().map(ShortLinkGroupRespDTO::getGid).toList()).getData();
        Map<String, Integer> gidCountMap = countRespDTOS.stream().collect(Collectors.toMap(ShortLinkGroupCountRespDTO::getGid, ShortLinkGroupCountRespDTO::getShortLinkCount));
        return shortLinkGroupRespDTOS.stream().peek(item -> item.setShortLinkCount(gidCountMap.getOrDefault(item.getGid(), 0))).toList();
    }

    @Override
    public void delete(String gid) {
        // 1、获取登录的用户名
        String username = UserContext.getUsername();
        // 2、将delFlag设为1
        LambdaUpdateWrapper<GroupDO> wrapper = Wrappers.lambdaUpdate(GroupDO.class)
                .eq(GroupDO::getUsername, username)
                .eq(GroupDO::getGid, gid)
                .eq(GroupDO::getDelFlag, 0);
        GroupDO groupDO = new GroupDO();
        groupDO.setDelFlag(1);
        update(groupDO, wrapper);
    }

    @Override
    public void sort(List<ShortLinkGroupSortReqDTO> requestParams) {
        requestParams.forEach(each -> {
            GroupDO groupDO = GroupDO.builder()
                    .sortOrder(each.getSortOrder())
                    .build();
            LambdaUpdateWrapper<GroupDO> wrapper = Wrappers.lambdaUpdate(GroupDO.class)
                    .eq(GroupDO::getUsername, UserContext.getUsername())
                    .eq(GroupDO::getGid, each.getGid())
                    .eq(GroupDO::getDelFlag, 0);

            update(groupDO, wrapper);
        });
    }
}
